home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / imake / imake.c < prev    next >
C/C++ Source or Header  |  1992-08-21  |  21KB  |  885 lines

  1. /* $XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $ */
  2.  
  3. /*****************************************************************************\
  4.  *                                                                           *
  5.  *                                Porting Note                               *
  6.  *                                                                           *
  7.  * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will be *
  8.  * passed to the template file.                                              *
  9.  *                                                                           *
  10. \*****************************************************************************/
  11.  
  12. /*
  13.  * 
  14.  * Copyright 1985, 1986, 1987 by the Massachusetts Institute of Technology
  15.  * 
  16.  * Permission to use, copy, modify, and distribute this
  17.  * software and its documentation for any purpose and without
  18.  * fee is hereby granted, provided that the above copyright
  19.  * notice appear in all copies and that both that copyright
  20.  * notice and this permission notice appear in supporting
  21.  * documentation, and that the name of M.I.T. not be used in
  22.  * advertising or publicity pertaining to distribution of the
  23.  * software without specific, written prior permission.
  24.  * M.I.T. makes no representations about the suitability of
  25.  * this software for any purpose.  It is provided "as is"
  26.  * without express or implied warranty.
  27.  * 
  28.  * Original Author:
  29.  *    Todd Brunhoff
  30.  *    Tektronix, inc.
  31.  *    While a guest engineer at Project Athena, MIT
  32.  *
  33.  * imake: the include-make program.
  34.  *
  35.  * Usage: imake [-Idir] [-Ddefine] [-T] [-f imakefile ] [-s] [-e] [-v] [make flags]
  36.  *
  37.  * Imake takes a template makefile (Imake.tmpl) and runs cpp on it
  38.  * producing a temporary makefile in /tmp.  It then runs make on
  39.  * this pre-processed makefile.
  40.  * Options:
  41.  *        -D    define.  Same as cpp -D argument.
  42.  *        -I    Include directory.  Same as cpp -I argument.
  43.  *        -T    template.  Designate a template other
  44.  *             than Imake.tmpl
  45.  *        -s[F]    show.  Show the produced makefile on the standard
  46.  *            output.  Make is not run is this case.  If a file
  47.  *            argument is provided, the output is placed there.
  48.  *              -e[F]   execute instead of show; optionally name Makefile F
  49.  *        -v    verbose.  Show the make command line executed.
  50.  *
  51.  * Environment variables:
  52.  *        
  53.  *        IMAKEINCLUDE    Include directory to use in addition to "."
  54.  *        IMAKECPP    Cpp to use instead of /lib/cpp
  55.  *        IMAKEMAKE    make program to use other than what is
  56.  *                found by searching the $PATH variable.
  57.  * Other features:
  58.  *    imake reads the entire cpp output into memory and then scans it
  59.  *    for occurences of "@@".  If it encounters them, it replaces it with
  60.  *    a newline.  It also trims any trailing white space on output lines
  61.  *    (because make gets upset at them).  This helps when cpp expands
  62.  *    multi-line macros but you want them to appear on multiple lines.
  63.  *
  64.  *    The macros MAKEFILE and MAKE are provided as macros
  65.  *    to make.  MAKEFILE is set to imake's makefile (not the constructed,
  66.  *    preprocessed one) and MAKE is set to argv[0], i.e. the name of
  67.  *    the imake program.
  68.  *
  69.  * Theory of operation:
  70.  *   1. Determine the name of the imakefile from the command line (-f)
  71.  *    or from the content of the current directory (Imakefile or imakefile).
  72.  *    Call this <imakefile>.  This gets added to the arguments for
  73.  *    make as MAKEFILE=<imakefile>.
  74.  *   2. Determine the name of the template from the command line (-T)
  75.  *    or the default, Imake.tmpl.  Call this <template>
  76.  *   3. Start up cpp an provide it with three lines of input:
  77.  *        #define IMAKE_TEMPLATE        " <template> "
  78.  *        #define INCLUDE_IMAKEFILE    < <imakefile> >
  79.  *        #include IMAKE_TEMPLATE
  80.  *    Note that the define for INCLUDE_IMAKEFILE is intended for
  81.  *    use in the template file.  This implies that the imake is
  82.  *    useless unless the template file contains at least the line
  83.  *        #include INCLUDE_IMAKEFILE
  84.  *   4. Gather the output from cpp, and clean it up, expanding @@ to
  85.  *    newlines, stripping trailing white space, cpp control lines,
  86.  *    and extra blank lines.  This cleaned output is placed in a
  87.  *    temporary file.  Call this <makefile>.
  88.  *   5. Start up make specifying <makefile> as its input.
  89.  *
  90.  * The design of the template makefile should therefore be:
  91.  *    <set global macros like CFLAGS, etc.>
  92.  *    <include machine dependent additions>
  93.  *    #include INCLUDE_IMAKEFILE
  94.  *    <add any global targets like 'clean' and long dependencies>
  95.  */
  96. #include <stdio.h>
  97. #if (defined(SVR4) || defined(_IBMR2) || defined(SYSV386)) && __STDC__
  98. FILE * fdopen();
  99. #endif
  100. #include <ctype.h>
  101. #include "Xosdefs.h"
  102. #ifndef X_NOT_POSIX
  103. #define _POSIX_SOURCE
  104. #endif
  105. #include <sys/types.h>
  106. #include <fcntl.h>
  107. #ifdef X_NOT_POSIX
  108. #include <sys/file.h>
  109. #else
  110. #include <unistd.h>
  111. #endif
  112. #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
  113. #include <signal.h>
  114. #else
  115. #define _POSIX_SOURCE
  116. #include <signal.h>
  117. #undef _POSIX_SOURCE
  118. #endif
  119. #include <sys/stat.h>
  120. #ifndef X_NOT_POSIX
  121. #ifdef _POSIX_SOURCE
  122. #include <sys/wait.h>
  123. #else
  124. #define _POSIX_SOURCE
  125. #include <sys/wait.h>
  126. #undef _POSIX_SOURCE
  127. #endif
  128. #define waitCode(w)    WEXITSTATUS(w)
  129. #define waitSig(w)    WTERMSIG(w)
  130. typedef int        waitType;
  131. #else /* X_NOT_POSIX */
  132. #ifdef SYSV
  133. #define waitCode(w)    (((w) >> 8) & 0x7f)
  134. #define waitSig(w)    ((w) & 0xff)
  135. typedef int        waitType;
  136. #else /* SYSV */
  137. #include <sys/wait.h>
  138. #define waitCode(w)    ((w).w_T.w_Retcode)
  139. #define waitSig(w)    ((w).w_T.w_Termsig)
  140. typedef union wait    waitType;
  141. #endif
  142. #ifndef WIFSIGNALED
  143. #define WIFSIGNALED(w) waitSig(w)
  144. #endif
  145. #ifndef WIFEXITED
  146. #define WIFEXITED(w) waitCode(w)
  147. #endif
  148. #endif /* X_NOT_POSIX */
  149. #ifndef X_NOT_STDC_ENV
  150. #include <stdlib.h>
  151. #else
  152. char *malloc(), *realloc();
  153. void exit();
  154. #endif
  155. #if defined(macII) && !defined(__STDC__)  /* stdlib.h fails to define these */
  156. char *malloc(), *realloc();
  157. #endif /* macII */
  158. #ifdef X_NOT_STDC_ENV
  159. extern char    *getenv();
  160. #endif
  161. #include <errno.h>
  162. extern int    errno;
  163. #include "imakemdep.h"
  164.  
  165.  
  166. #define    TRUE        1
  167. #define    FALSE        0
  168.  
  169. #ifdef FIXUP_CPP_WHITESPACE
  170. int    InRule = FALSE;
  171. #endif
  172.  
  173. /*
  174.  * Some versions of cpp reduce all tabs in macro expansion to a single
  175.  * space.  In addition, the escaped newline may be replaced with a
  176.  * space instead of being deleted.  Blech.
  177.  */
  178. #ifndef FIXUP_CPP_WHITESPACE
  179. #define KludgeOutputLine(arg)
  180. #define KludgeResetRule()
  181. #endif
  182.  
  183. typedef    unsigned char    boolean;
  184.  
  185. #ifndef DEFAULT_CPP
  186. #ifdef USE_CC_E
  187. #define DEFAULT_CPP "/bin/cc"
  188. #else
  189. #ifdef CPP_PROGRAM
  190. #define DEFAULT_CPP CPP_PROGRAM
  191. #else
  192. #define DEFAULT_CPP "/lib/cpp"
  193. #endif
  194. #endif
  195. #endif
  196.  
  197. char *cpp = DEFAULT_CPP;
  198.  
  199. char    *tmpMakefile    = "/tmp/Imf.XXXXXX";
  200. char    *tmpImakefile    = "/tmp/IIf.XXXXXX";
  201. char    *make_argv[ ARGUMENTS ] = { "make" };
  202.  
  203. int    make_argindex;
  204. int    cpp_argindex;
  205. char    *make = NULL;
  206. char    *Imakefile = NULL;
  207. char    *Makefile = "Makefile";
  208. char    *Template = "Imake.tmpl";
  209. char    *program;
  210. char    *FindImakefile();
  211. char    *ReadLine();
  212. char    *CleanCppInput();
  213. char    *Strdup();
  214. char    *Emalloc();
  215.  
  216. #ifdef sprite
  217. char    *targetMachine;
  218. #endif
  219.  
  220. boolean    verbose = FALSE;
  221. boolean    show = TRUE;
  222.  
  223. main(argc, argv)
  224.     int    argc;
  225.     char    **argv;
  226. {
  227.     FILE    *tmpfd;
  228.     char    makeMacro[ BUFSIZ ];
  229.     char    makefileMacro[ BUFSIZ ];
  230.  
  231.     program = argv[0];
  232.     init();
  233.     SetOpts(argc, argv);
  234. #ifdef sprite
  235.     AddCppArg("-I/sprite/lib/imake");
  236. #ifndef ds3100
  237.     AddCppArg("-traditional");
  238. #endif
  239.     AddCppArg("-Dsprite");
  240.     if (targetMachine == NULL) {
  241.         /*
  242.          * If no target machine was specified on the command line,
  243.          * then default to the current machine type.
  244.          */
  245. #ifdef sun3
  246.         targetMachine = "sun3";
  247. #endif
  248. #ifdef sun4
  249.         targetMachine = "sun4";
  250. #endif
  251. #ifdef ds3100
  252.         targetMachine = "ds3100";
  253. #endif
  254.     }
  255.     if (strcmp(targetMachine, "sun3") == 0) {
  256.         AddCppArg("-Dsun");
  257.         AddCppArg("-Dsun3");
  258.     } else if (strcmp(targetMachine,"sun4") == 0) {
  259.         AddCppArg("-Dsun");
  260.         AddCppArg("-Dsun4");
  261.     } else if (strcmp(targetMachine,"sun4c") == 0) {
  262.         AddCppArg("-Dsun");
  263.         AddCppArg("-Dsun4");
  264.         AddCppArg("-Dsun4c");
  265.     } else if (strcmp(targetMachine, "ds3100") == 0) {
  266.         AddCppArg("-Dds3100");
  267.         AddCppArg("-Dmips");
  268.     } else if (strcmp(targetMachine, "ds5000") == 0) {
  269.         AddCppArg("-Dds5000");
  270.         AddCppArg("-Dmips");
  271.     } else {
  272.         fprintf(stderr, "Unknown target machine: %s\n", targetMachine);
  273.         exit(1);
  274.     }
  275. #endif
  276.  
  277. #ifdef USE_CC_E
  278.     AddCppArg("-");
  279. #endif
  280.  
  281.     Imakefile = FindImakefile(Imakefile);
  282.     if (Makefile)
  283.         tmpMakefile = Makefile;
  284.     else {
  285.         tmpMakefile = Strdup(tmpMakefile);
  286.         (void) mktemp(tmpMakefile);
  287.     }
  288.     AddMakeArg("-f");
  289.     AddMakeArg( tmpMakefile );
  290.     sprintf(makeMacro, "MAKE=%s", program);
  291.     AddMakeArg( makeMacro );
  292.     sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
  293.     AddMakeArg( makefileMacro );
  294.  
  295.     if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
  296.         LogFatal("Cannot create temporary file %s.", tmpMakefile);
  297.  
  298.     cppit(Imakefile, Template, tmpfd, tmpMakefile);
  299.  
  300.     if (show) {
  301.         if (Makefile == NULL)
  302.             showit(tmpfd);
  303.     } else
  304.         makeit();
  305.     wrapup();
  306.     exit(0);
  307. }
  308.  
  309. showit(fd)
  310.     FILE    *fd;
  311. {
  312.     char    buf[ BUFSIZ ];
  313.     int    red;
  314.  
  315.     fseek(fd, 0, 0);
  316.     while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
  317.         fwrite(buf, red, 1, stdout);
  318.     if (red < 0)
  319.         LogFatal("Cannot write stdout.", "");
  320. }
  321.  
  322. wrapup()
  323. {
  324.     if (tmpMakefile != Makefile)
  325.         unlink(tmpMakefile);
  326.     unlink(tmpImakefile);
  327. }
  328.  
  329. #ifdef SIGNALRETURNSINT
  330. int
  331. #else
  332. void
  333. #endif
  334. catch(sig)
  335.     int    sig;
  336. {
  337.     errno = 0;
  338.     LogFatalI("Signal %d.", sig);
  339. }
  340.  
  341. /*
  342.  * Initialize some variables.
  343.  */
  344. init()
  345. {
  346.     char    *p;
  347.  
  348.     make_argindex=0;
  349.     while (make_argv[ make_argindex ] != NULL)
  350.         make_argindex++;
  351.     cpp_argindex = 0;
  352.     while (cpp_argv[ cpp_argindex ] != NULL)
  353.         cpp_argindex++;
  354.  
  355.     /*
  356.      * See if the standard include directory is different than
  357.      * the default.  Or if cpp is not the default.  Or if the make
  358.      * found by the PATH variable is not the default.
  359.      */
  360.     if (p = getenv("IMAKEINCLUDE")) {
  361.         if (*p != '-' || *(p+1) != 'I')
  362.             LogFatal("Environment var IMAKEINCLUDE %s\n",
  363.                 "must begin with -I");
  364.         AddCppArg(p);
  365.         for (; *p; p++)
  366.             if (*p == ' ') {
  367.                 *p++ = '\0';
  368.                 AddCppArg(p);
  369.             }
  370.     }
  371.     if (p = getenv("IMAKECPP"))
  372.         cpp = p;
  373.     if (p = getenv("IMAKEMAKE"))
  374.         make = p;
  375.  
  376.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  377.         signal(SIGINT, catch);
  378. }
  379.  
  380. AddMakeArg(arg)
  381.     char    *arg;
  382. {
  383.     errno = 0;
  384.     if (make_argindex >= ARGUMENTS-1)
  385.         LogFatal("Out of internal storage.", "");
  386.     make_argv[ make_argindex++ ] = arg;
  387.     make_argv[ make_argindex ] = NULL;
  388. }
  389.  
  390. AddCppArg(arg)
  391.     char    *arg;
  392. {
  393.     errno = 0;
  394.     if (cpp_argindex >= ARGUMENTS-1)
  395.         LogFatal("Out of internal storage.", "");
  396.     cpp_argv[ cpp_argindex++ ] = arg;
  397.     cpp_argv[ cpp_argindex ] = NULL;
  398. }
  399.  
  400. SetOpts(argc, argv)
  401.     int    argc;
  402.     char    **argv;
  403. {
  404.     errno = 0;
  405.     /*
  406.      * Now gather the arguments for make
  407.      */
  408.     for(argc--, argv++; argc; argc--, argv++) {
  409.         /*
  410.          * We intercept these flags.
  411.          */
  412.         if (argv[0][0] == '-') {
  413.         if (argv[0][1] == 'D') {
  414.             AddCppArg(argv[0]);
  415.         } else if (argv[0][1] == 'I') {
  416.             AddCppArg(argv[0]);
  417.         } else if (argv[0][1] == 'f') {
  418.             if (argv[0][2])
  419.             Imakefile = argv[0]+2;
  420.             else {
  421.             argc--, argv++;
  422.             if (! argc)
  423.                 LogFatal("No description arg after -f flag\n", "");
  424.             Imakefile = argv[0];
  425.             }
  426.         } else if (argv[0][1] == 's') {
  427.             if (argv[0][2])
  428.             Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
  429.                 NULL : argv[0]+2;
  430.             else {
  431.             argc--, argv++;
  432.             if (!argc)
  433.                 LogFatal("No description arg after -s flag\n", "");
  434.             Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
  435.                 NULL : argv[0];
  436.             }
  437.             show = TRUE;
  438.         } else if (argv[0][1] == 'e') {
  439.            Makefile = (argv[0][2] ? argv[0]+2 : NULL);
  440.            show = FALSE;
  441.         } else if (argv[0][1] == 'T') {
  442.             if (argv[0][2])
  443.             Template = argv[0]+2;
  444.             else {
  445.             argc--, argv++;
  446.             if (! argc)
  447.                 LogFatal("No description arg after -T flag\n", "");
  448.             Template = argv[0];
  449.             }
  450. #ifdef sprite            
  451.         } else if (argv[0][1] == 'm') {
  452.             if (argv[0][2])
  453.             targetMachine = argv[0]+2;
  454.             else {
  455.             argc--, argv++;
  456.             if (! argc)
  457.                 LogFatal("No targetMachine arg after -m flag\n", "");
  458.             targetMachine = argv[0];
  459.             }
  460. #endif            
  461.         } else if (argv[0][1] == 'v') {
  462.             verbose = TRUE;
  463.         } else
  464.             AddMakeArg(argv[0]);
  465.         } else
  466.         AddMakeArg(argv[0]);
  467.     }
  468. }
  469.  
  470. char *FindImakefile(Imakefile)
  471.     char    *Imakefile;
  472. {
  473.     int    fd;
  474.  
  475.     if (Imakefile) {
  476.         if ((fd = open(Imakefile, O_RDONLY)) < 0)
  477.             LogFatal("Cannot open %s.", Imakefile);
  478.     } else {
  479.         if ((fd = open("Imakefile", O_RDONLY)) < 0)
  480.             if ((fd = open("imakefile", O_RDONLY)) < 0)
  481.                 LogFatal("No description file.", "");
  482.             else
  483.                 Imakefile = "imakefile";
  484.         else
  485.             Imakefile = "Imakefile";
  486.     }
  487.     close (fd);
  488.     return(Imakefile);
  489. }
  490.  
  491. LogFatalI(s, i)
  492.     char *s;
  493.     int i;
  494. {
  495.     /*NOSTRICT*/
  496.     LogFatal(s, (char *)i);
  497. }
  498.  
  499. LogFatal(x0,x1)
  500.     char *x0, *x1;
  501. {
  502.     extern char    *sys_errlist[];
  503.     static boolean    entered = FALSE;
  504.  
  505.     if (entered)
  506.         return;
  507.     entered = TRUE;
  508.  
  509.     fprintf(stderr, "%s: ", program);
  510.     if (errno)
  511.         fprintf(stderr, "%s: ", sys_errlist[ errno ]);
  512.     fprintf(stderr, x0,x1);
  513.     fprintf(stderr, "  Stop.\n");
  514.     wrapup();
  515.     exit(1);
  516. }
  517.  
  518. showargs(argv)
  519.     char    **argv;
  520. {
  521.     for (; *argv; argv++)
  522.         fprintf(stderr, "%s ", *argv);
  523.     fprintf(stderr, "\n");
  524. }
  525.  
  526. cppit(Imakefile, template, outfd, outfname)
  527.     char    *Imakefile;
  528.     char    *template;
  529.     FILE    *outfd;
  530.     char    *outfname;
  531. {
  532.     FILE    *pipeFile;
  533.     int    pid, pipefd[2];
  534.     waitType    status;
  535.     char    *cleanedImakefile;
  536.  
  537.     /*
  538.      * Get a pipe.
  539.      */
  540.     if (pipe(pipefd) < 0)
  541.         LogFatal("Cannot make a pipe.", "");
  542.  
  543.     /*
  544.      * Fork and exec cpp
  545.      */
  546.     pid = fork();
  547.     if (pid < 0)
  548.         LogFatal("Cannot fork.", "");
  549.     if (pid) {    /* parent */
  550.         close(pipefd[0]);
  551.         cleanedImakefile = CleanCppInput(Imakefile);
  552.         if ((pipeFile = fdopen(pipefd[1], "w")) == NULL)
  553.             LogFatalI("Cannot fdopen fd %d for output.", pipefd[1]);
  554.         fprintf(pipeFile, "#define IMAKE_TEMPLATE\t\"%s\"\n",
  555.             template);
  556.         fprintf(pipeFile, "#define INCLUDE_IMAKEFILE\t<%s>\n",
  557.             cleanedImakefile);
  558.         fprintf(pipeFile, "#include IMAKE_TEMPLATE\n");
  559.         fclose(pipeFile);
  560.         while (wait(&status) > 0) {
  561.             errno = 0;
  562.             if (WIFSIGNALED(status))
  563.                 LogFatalI("Signal %d.", waitSig(status));
  564.             if (WIFEXITED(status) && waitCode(status))
  565.                 LogFatalI("Exit code %d.", waitCode(status));
  566.         }
  567.         CleanCppOutput(outfd, outfname);
  568.     } else {    /* child... dup and exec cpp */
  569.         if (verbose)
  570.             showargs(cpp_argv);
  571.         dup2(pipefd[0], 0);
  572.         dup2(fileno(outfd), 1);
  573.         close(pipefd[1]);
  574.         execv(cpp, cpp_argv);
  575.         LogFatal("Cannot exec %s.", cpp);
  576.     }
  577. }
  578.  
  579. makeit()
  580. {
  581.     int    pid;
  582.     waitType    status;
  583.  
  584.     /*
  585.      * Fork and exec make
  586.      */
  587.     pid = fork();
  588.     if (pid < 0)
  589.         LogFatal("Cannot fork.", "");
  590.     if (pid) {    /* parent... simply wait */
  591.         while (wait(&status) > 0) {
  592.             errno = 0;
  593.             if (WIFSIGNALED(status))
  594.                 LogFatalI("Signal %d.", waitSig(status));
  595.             if (WIFEXITED(status) && waitCode(status))
  596.                 LogFatalI("Exit code %d.", waitCode(status));
  597.         }
  598.     } else {    /* child... dup and exec cpp */
  599.         if (verbose)
  600.             showargs(make_argv);
  601.         if (make)
  602.             execv(make, make_argv);
  603.         else
  604.             execvp("make", make_argv);
  605.         LogFatal("Cannot exec %s.", make);
  606.     }
  607. }
  608.  
  609. char *CleanCppInput(Imakefile)
  610.     char    *Imakefile;
  611. {
  612.     FILE    *outFile = NULL;
  613.     int    infd;
  614.     char    *buf,        /* buffer for file content */
  615.         *pbuf,        /* walking pointer to buf */
  616.         *punwritten,    /* pointer to unwritten portion of buf */
  617.         *cleanedImakefile = Imakefile,    /* return value */
  618.         *ptoken,    /* pointer to # token */
  619.         *pend,        /* pointer to end of # token */
  620.         savec;        /* temporary character holder */
  621.     struct stat    st;
  622.  
  623.     /*
  624.      * grab the entire file.
  625.      */
  626.     if ((infd = open(Imakefile, O_RDONLY)) < 0)
  627.         LogFatal("Cannot open %s for input.", Imakefile);
  628.     fstat(infd, &st);
  629.     buf = Emalloc(st.st_size+1);
  630.     if (read(infd, buf, st.st_size) != st.st_size)
  631.         LogFatal("Cannot read all of %s:", Imakefile);
  632.     close(infd);
  633.     buf[ st.st_size ] = '\0';
  634.  
  635.     punwritten = pbuf = buf;
  636.     while (*pbuf) {
  637.         /* pad make comments for cpp */
  638.         if (*pbuf == '#' && (pbuf == buf || pbuf[-1] == '\n')) {
  639.  
  640.         ptoken = pbuf+1;
  641.         while (*ptoken == ' ' || *ptoken == '\t')
  642.             ptoken++;
  643.         pend = ptoken;
  644.         while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
  645.             pend++;
  646.         savec = *pend;
  647.         *pend = '\0';
  648.         if (strcmp(ptoken, "include")
  649.          && strcmp(ptoken, "define")
  650.          && strcmp(ptoken, "undef")
  651.          && strcmp(ptoken, "ifdef")
  652.          && strcmp(ptoken, "ifndef")
  653.          && strcmp(ptoken, "else")
  654.          && strcmp(ptoken, "endif")
  655.          && strcmp(ptoken, "if")) {
  656.             if (outFile == NULL) {
  657.             tmpImakefile = Strdup(tmpImakefile);
  658.             (void) mktemp(tmpImakefile);
  659.             cleanedImakefile = tmpImakefile;
  660.             outFile = fopen(tmpImakefile, "w");
  661.             if (outFile == NULL)
  662.                 LogFatal("Cannot open %s for write.\n",
  663.                 tmpImakefile);
  664.             }
  665.             fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
  666.             fputs("/**/", outFile);
  667.             punwritten = pbuf;
  668.         }
  669.         *pend = savec;
  670.         }
  671.         pbuf++;
  672.     }
  673.     if (outFile) {
  674.         fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
  675.         fclose(outFile); /* also closes the pipe */
  676.     }
  677.  
  678.     return(cleanedImakefile);
  679. }
  680.  
  681. CleanCppOutput(tmpfd, tmpfname)
  682.     FILE    *tmpfd;
  683.     char    *tmpfname;
  684. {
  685.     char    *input;
  686.     int    blankline = 0;
  687.  
  688.     while(input = ReadLine(tmpfd, tmpfname)) {
  689.         if (isempty(input)) {
  690.             if (blankline++)
  691.                 continue;
  692.             KludgeResetRule();
  693.         } else {
  694.             blankline = 0;
  695.             KludgeOutputLine(&input);
  696.             fputs(input, tmpfd);
  697.         }
  698.         putc('\n', tmpfd);
  699.     }
  700.     fflush(tmpfd);
  701. #ifdef NFS_STDOUT_BUG
  702.     /*
  703.      * On some systems, NFS seems to leave a large number of nulls at
  704.      * the end of the file.  Ralph Swick says that this kludge makes the
  705.      * problem go away.
  706.      */
  707.     ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
  708. #endif
  709. }
  710.  
  711. /*
  712.  * Determine of a line has nothing in it.  As a side effect, we trim white
  713.  * space from the end of the line.  Cpp magic cookies are also thrown away.
  714.  */
  715. isempty(line)
  716.     char    *line;
  717. {
  718.     char    *pend;
  719.  
  720.     /*
  721.      * Check for lines of the form
  722.      *    # n "...
  723.      * or
  724.      *    # line n "...
  725.      */
  726.     if (*line == '#') {
  727.         pend = line+1;
  728.         if (*pend == ' ')
  729.             pend++;
  730.         if (strncmp(pend, "line ", 5) == 0)
  731.             pend += 5;
  732.         if (isdigit(*pend)) {
  733.             while (isdigit(*pend))
  734.                 pend++;
  735.             if (*pend++ == ' ' && *pend == '"')
  736.                 return(TRUE);
  737.         }
  738.     }
  739.  
  740.     /*
  741.      * Find the end of the line and then walk back.
  742.      */
  743.     for (pend=line; *pend; pend++) ;
  744.  
  745.     pend--;
  746.     while (pend >= line && (*pend == ' ' || *pend == '\t'))
  747.         pend--;
  748.     *++pend = '\0';
  749.     return (*line == '\0');
  750. }
  751.  
  752. /*ARGSUSED*/
  753. char *ReadLine(tmpfd, tmpfname)
  754.     FILE    *tmpfd;
  755.     char    *tmpfname;
  756. {
  757.     static boolean    initialized = FALSE;
  758.     static char    *buf, *pline, *end;
  759.     char    *p1, *p2;
  760.  
  761.     if (! initialized) {
  762.         int    total_red;
  763.         struct stat    st;
  764.  
  765.         /*
  766.          * Slurp it all up.
  767.          */
  768.         fseek(tmpfd, 0, 0);
  769.         fstat(fileno(tmpfd), &st);
  770.         pline = buf = Emalloc(st.st_size+1);
  771.         total_red = read(fileno(tmpfd), buf, st.st_size);
  772.         if (total_red != st.st_size)
  773.             LogFatal("cannot read %s\n", tmpMakefile);
  774.         end = buf + st.st_size;
  775.         *end = '\0';
  776.         lseek(fileno(tmpfd), 0, 0);
  777. #ifdef SYSV
  778.         freopen(tmpfname, "w+", tmpfd);
  779. #else    /* !SYSV */
  780.         ftruncate(fileno(tmpfd), 0);
  781. #endif    /* !SYSV */
  782.         initialized = TRUE;
  783.         fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
  784.         fprintf (tmpfd, "# %s\n",
  785.         "$XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $");
  786.  
  787. #ifdef FIXUP_CPP_WHITESPACE
  788.         {
  789.         static char *cpp_warning[] = {
  790. "#",
  791. "# The cpp used on this machine replaces all newlines and multiple tabs and",
  792. "# spaces in a macro expansion with a single space.  Imake tries to compensate",
  793. "# for this, but is not always successful.",
  794. "#",
  795. NULL };
  796.         char **cpp;
  797.  
  798.         for (cpp = cpp_warning; *cpp; cpp++) {
  799.             fprintf (tmpfd, "%s\n", *cpp);
  800.         }
  801.         }
  802. #endif /* FIXUP_CPP_WHITESPACE */
  803.     }
  804.  
  805.     for (p1 = pline; p1 < end; p1++) {
  806.         if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */
  807.             *p1++ = '\0';
  808.             p1++; /* skip over second @ */
  809.             break;
  810.         }
  811.         else if (*p1 == '\n') { /* real EOL */
  812.             *p1++ = '\0';
  813.             break;
  814.         }
  815.     }
  816.  
  817.     /*
  818.      * return NULL at the end of the file.
  819.      */
  820.     p2 = (pline == p1 ? NULL : pline);
  821.     pline = p1;
  822.     return(p2);
  823. }
  824.  
  825. writetmpfile(fd, buf, cnt)
  826.     FILE    *fd;
  827.     int    cnt;
  828.     char    *buf;
  829. {
  830.     errno = 0;
  831.     if (fwrite(buf, cnt, 1, fd) != 1)
  832.         LogFatal("Cannot write to %s.", tmpMakefile);
  833. }
  834.  
  835. char *Emalloc(size)
  836.     int    size;
  837. {
  838.     char    *p;
  839.  
  840.     if ((p = malloc(size)) == NULL)
  841.         LogFatalI("Cannot allocate %d bytes\n", size);
  842.     return(p);
  843. }
  844.  
  845. #ifdef FIXUP_CPP_WHITESPACE
  846. KludgeOutputLine(pline)
  847.     char    **pline;
  848. {
  849.     char    *p = *pline;
  850.  
  851.     switch (*p) {
  852.         case '#':    /*Comment - ignore*/
  853.         break;
  854.         case '\t':    /*Already tabbed - ignore it*/
  855.             break;
  856.         case ' ':    /*May need a tab*/
  857.         default:
  858.         for (; *p; p++) if (p[0] == ':' && 
  859.                     p > *pline && p[-1] != '\\') {
  860.             if (**pline == ' ')
  861.             (*pline)++;
  862.             InRule = TRUE;
  863.             break;
  864.         }
  865.         if (InRule && **pline == ' ')
  866.             **pline = '\t';
  867.         break;
  868.     }
  869. }
  870.  
  871. KludgeResetRule()
  872. {
  873.     InRule = FALSE;
  874. }
  875. #endif /* FIXUP_CPP_WHITESPACE */
  876.  
  877. char *Strdup(cp)
  878.     register char *cp;
  879. {
  880.     register char *new = Emalloc(strlen(cp) + 1);
  881.  
  882.     strcpy(new, cp);
  883.     return new;
  884. }
  885.